package away3d.core.render ;


import away3d.cameras.Camera3D ;
import away3d.core.base.IRenderable ;
import away3d.core.data.RenderableListItem ;
import away3d.core.managers.Stage3DProxy ;
import away3d.core.traverse.EntityCollector ;
import away3d.materials.MaterialBase ;

import flash.display3D.Context3DBlendFactor ;
import flash.display3D.Context3DCompareMode ;




/**
 * The DefaultRenderer class provides the default rendering method. It renders the scene graph objects using the
 * materials assigned to them.
 */
class DefaultRenderer extends RendererBase
{
    
    
    private var _activeMaterial : MaterialBase ;
    
    
    
    /**
     * Creates a new DefaultRenderer object.
     * @param antiAlias The amount of anti-aliasing to use.
     * @param renderMode The render mode to use.
     */
    public function DefaultRenderer( ?antiAlias : Int = 0, ?renderMode : String = "auto" )
    {
        
        super( antiAlias, true, renderMode ) ;
        
    }
    
    
    public override function set stage3DProxy( value : Stage3DProxy )
    {
        
        super.stage3DProxy = value ;
        
    }
    
    
    /**
     * @inheritDoc
     */
    override private function draw( entityCollector : EntityCollector )
    {
        
        _context.setDepthTest( true, Context3DCompareMode.LESS ) ;
        
        _context.setBlendFactors( Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO ) ;
        drawRenderables( entityCollector.opaqueRenderableHead, entityCollector ) ;
        
        _context.setDepthTest( false, Context3DCompareMode.LESS ) ;
        
        if( entityCollector.skyBox )
        {
            
            if( _activeMaterial ) _activeMaterial.deactivate( _context ) ;
            
            _activeMaterial = null ;
            drawSkyBox( entityCollector ) ;
            
        }
        
        drawRenderables( entityCollector.blendedRenderableHead, entityCollector ) ;
        
        if( _activeMaterial ) _activeMaterial.deactivate( _context ) ;
        
        _activeMaterial = null ;
        
    }
    
    
    /**
     * Draw the skybox if present.
     * @param entityCollector The EntityCollector containing all potentially visible information.
     */
    private function drawSkyBox( entityCollector : EntityCollector )
    {
        
        var skyBox      = entityCollector.skyBox ;
        var material    = skyBox.material ;
        var camera      = entityCollector.camera ;
        
        material.activatePass( 0, _context, _contextIndex, camera ) ;
        material.renderPass( 0, skyBox, _context, _contextIndex, camera ) ;
        material.deactivatePass( 0, _context ) ;
        
    }
    
    
    /**
     * Draw a list of renderables.
     * @param renderables The renderables to draw.
     * @param entityCollector The EntityCollector containing all potentially visible information.
     */
    private function drawRenderables( item : RenderableListItem, entityCollector : EntityCollector )
    {
        
        var renderable  : IRenderable ;
        var numPasses   : Int  ;
        var j           : Int ;
        var camera      = entityCollector.camera ;
        var item2       : RenderableListItem ;
        
        while( item )
        {
            
            _activeMaterial = item.renderable.material ;
            _activeMaterial.updateMaterial( _context ) ;
            
            numPasses = _activeMaterial.numPasses ;
            j = 0 ;
            
            do
            {
                
                item2 = item ;
                _activeMaterial.activatePass( j, _context, _contextIndex, camera ) ;
                do 
                {
                    
                    _activeMaterial.renderPass( j, item2.renderable, _context, _contextIndex, camera ) ;
                    item2 = item2.next ;
                    
                } while( item2 && item2.renderable.material == _activeMaterial ) ;
                
                _activeMaterial.deactivatePass( j, _context ) ;
                
            } while ( ++j < numPasses ) ;
            
            item = item2 ;
            
        }
        
    }
    
    
}